// 注意：
// 此模块的 alloc/alloc_xxx/free/free_xxx/ 系列函数和 malloc 行为类似
// 分配的单位是字节而不是长度(长度转换成字节还需要乘以单个元素的大小)
//
// 而 default_alloc<T>/default_free<T> 则是兼容 ialloc<T> 接口的，
// 分配的单位是长度，内部会自己转换成对应的字节大小
#ifndef xpack_utils_memory
#define xpack_utils_memory
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::utils_memory::inc
#include"macro/xexport.hpp"
#include"macro/xforward.hpp"
#include"macro/xtypeid.hpp"
#include"macro/xmaybe_unused.hpp"
#include"macro/xnew.hpp"
#include"meta/is_same.hpp"
#pragma pop_macro("xuser")

#define xsizeof(...)       \
    ::mixc::utils_memory::origin::memory::size{ sizeof(__VA_ARGS__) }

namespace mixc::utils_memory{
    extern voidp tiny_alloc(xmaybe_unused asciis name, uxx bytes);
    extern void  tiny_free(xmaybe_unused asciis name, voidp ptr, uxx bytes);

    template<class type_t>
    struct destroy{
        type_t data;
    };

    template<>
    struct destroy<void>{};
}

namespace mixc::utils_memory::origin::memory{
    struct size{
        constexpr size() : 
            value(0){
        }

        constexpr explicit size(uxx value) : 
            value(value){
        }

        friend size operator * (size left, auto const & right) {
            return size(left.value * uxx(right));
        }

        friend size operator * (auto const & left, size right){
            return size(right.value * uxx(left));
        }

        friend size operator * (size left, size right){
            return size(right.value * left.value);
        }

        friend size operator + (size left, auto const & right){
            return size(left.value + uxx(right));
        }

        friend size operator + (auto const & left, size right){
            return size(uxx(right) + uxx(left));
        }

        friend size operator + (size left, size right){
            return size(right.value + left.value);
        }

        friend size operator - (size left, auto const & right){
            return size(left.value - uxx(right));
        }

        friend size operator - (auto const & left, size right){
            return size(uxx(left) - right.value);
        }

        friend size operator - (size left, size right){
            return size(left.value - right.value);
        }

        constexpr operator uxx (){
            return value;
        }
    private:
        uxx value;
    };

    extern voidp malloc(uxx bytes);
    extern voidp malloc_aligned(uxx bytes, uxx align_bytes);
    extern void  mfree(voidp ptr);
    extern void  mfree_aligned(voidp ptr);

    template<class type_t, class ... args_t>
    inline type_t * alloc_with_initial(size bytes, args_t && ... list){
        auto ptr = (type_t *)tiny_alloc(xtypeid(type_t).name, bytes);
        return xnew(ptr) type_t(xforward(list)...);
    }

    template<class type_t, class ... args_t>
    inline type_t * alloc_with_initial(args_t && ... list){
        return alloc_with_initial<type_t>(xsizeof(type_t), xforward(list)...);
    }

    template<class type_t>
    inline type_t * alloc(size bytes){
        auto ptr = (type_t *)tiny_alloc(xtypeid(type_t).name, bytes);
        return ptr;
    }

    template<class type_t>
    inline type_t * alloc(){
        return alloc<type_t>(xsizeof(type_t));
    }

    template<class type_t>
    inline void free(type_t const * mem, size bytes){
        // 移除 const 修饰符号，避免 char const * 在 xdebug 中当作字符串处理了
        auto ptr = (type_t*)mem;
        tiny_free(xtypeid(type_t).name, (type_t *)ptr, bytes);
    }

    template<class type_t>
    inline void free(type_t const * ptr){
        free(ptr, xsizeof(type_t));
    }

    template<class type_t>
    inline void free_with_destroy(type_t const * ptr, size bytes){
        using destroy_wrapper = destroy<type_t> *;
        using destroy_wrapperp = destroy_wrapper *;
        destroy_wrapperp(ptr)->~destroy_wrapper();
        free(ptr, bytes);
    }

    template<class type_t>
    inline void free_with_destroy(type_t const * ptr){
        free_with_destroy(ptr, xsizeof(type_t));
    }

    struct default_allocator_t{
        constexpr default_allocator_t() : dummy(false){
            (void)dummy;
        }

        template<class type_t>
        static void free_with_destroy(const type_t * ptr, size bytes = xsizeof(type_t)){
            memory::free_with_destroy(ptr, bytes);
        }

        // 只分配，不初始化
        template<class type_t>
        static type_t * alloc(size bytes = xsizeof(type_t)){
            return memory::alloc<type_t>(bytes);
        }
    private:
        // for GCC12.3 bug
        bool dummy;
    };

    template<class default_allocator_t>
    concept is_allocator = requires(default_allocator_t allocator, asciis * alloc_ret, asciis item){
        default_allocator_t::free_with_destroy(item);
        default_allocator_t::free_with_destroy(item, xsizeof(item));
        alloc_ret = default_allocator_t::template alloc<asciis>();
        alloc_ret = default_allocator_t::template alloc<asciis>(xsizeof(asciis));
    };

    template<class type_t>
    constexpr auto default_alloc = [](uxx length) -> type_t * {
        if constexpr (inc::is_same<void, type_t>){
            return alloc<type_t>(xsizeof(char) * length);
        }
        else{
            return alloc<type_t>(xsizeof(type_t) * length);
        }
    };

    template<class type_t>
    constexpr auto default_free = [](type_t * ptr, uxx length){
        if constexpr (inc::is_same<void, type_t>){
            return free(ptr, xsizeof(char) * length);
        }
        else{
            free(ptr, xsizeof(type_t) * length);
        }
    };

    constexpr default_allocator_t default_allocator{};

    extern uxx  used_bytes();
    extern uxx  alive_object();
    extern uxx  alive_pages();
    extern void handle_async_memory_event();
}

#endif

xexport_space(mixc::utils_memory::origin)